# FeedLibrary - Library for RSS-feeds
# Copyright (C) 2007 Lauri Taimila
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

__licence__ = "GPLv2"
__copyright__ = "2007, Lauri Taimila"
__author__ = "Lauri Taimila <lauri@taimila.com>"

import os
from pysqlite2 import dbapi2 as sqlite

################################################################################
# This file contains three classes that together consists feed library 
# interface. These classes are FeedLibrary, Feed and Entry.
################################################################################

class FeedLibrary(object):
    """
    Feed library
    
    This library can be used to handle feeds in Entertainer.
    """
    
    # Feed cache database
    FEED_DB = os.path.expanduser('~/.entertainer/cache/feed.db')
    
    def __init__(self, backend_connection):
        """
        Initialize library
        @param backend_connection: BackendConnection object
        """
        self.backend_connection = backend_connection
        self.empty = False
        if not os.path.exists(self.__class__.FEED_DB):
            self.empty = True
        
    def add_feed(self, url):
        """
        Add feed to the library.
        @param url: URL of the feed
        """
        print "not functional yet"
        pass #FIXME: Edit conf file and emit message to the backend
        
    def remove_feed(self, url):
        """
        Remove feed from the library.
        @param url: URL of the feed
        """
        print "not functional yet"
        pass #FIXME: Edit conf file and emit message to the backend
 
    def is_empty(self):
        """
        Is feed library empty
        @return True if library is empty, otherwise false
        """
        return self.empty
        
    def get_feeds(self, order='TITLE'):
        """
        Get all feeds from the library. Feeds are fetched from the feed cache 
        database. This means that when this method is called you will always
        get up-to-date feedlist.
        
        @param order: Order of returned feeds: 'TITLE' or 'UNREAD'
        @return List of 'Feed' objects
        """
        if self.is_empty():
            return []
        else:
            feeds = []
            connection = sqlite.connect(self.__class__.FEED_DB)
            cursor = connection.cursor()
            cursor.execute("SELECT url FROM feed ORDER BY title")
            for row in cursor:
                feeds.append(Feed(row[0]))
            connection.close()
            return feeds
    
    def get_latest_entries(self, number=10):
        """
        Get the latest entries from the library.
        @param number: The maximum number of entries to be returned
        @return: List that contains tuples (Feed object, Entry object)
        """
        if self.is_empty():
            return []
        else:
            latest = []
            connection = sqlite.connect(self.__class__.FEED_DB)
            cursor = connection.cursor()
            cursor.execute("""SELECT DISTINCT feed.url, entry.id
                              FROM feed, entry
                              WHERE entry.feed_url = feed.url
                              ORDER BY entry.date, entry.time 
                              LIMIT 0,:max""",
                              { "max" : number } )
            for row in cursor:
                feed = Feed(row[0])
                entry = feed.get_entry(row[1])
                latest.append((feed, entry))
            connection.close()
            return latest
      
    def number_of_feeds(self):
        """
        Get number of the feeds in this library
        @return Number of feeds (integer)
        """
        if self.is_empty():
            return 0
        else:
            connection = sqlite.connect(self.__class__.FEED_DB)
            cursor = connection.cursor()
            cursor.execute("SELECT COUNT(url) FROM feed")
            result = cursor.fetchall()
            connection.close()
            return result[0][0]
    
    def number_of_unread_entries(self):
        """
        Get total number of unread entries in this library.
        @return integer value
        """
        if self.is_empty():
            return 0
        else:
            connection = sqlite.connect(self.__class__.FEED_DB)
            cursor = connection.cursor()
            cursor.execute("""SELECT COUNT(feed_url) FROM entry WHERE isread='NO'""")
            result = cursor.fetchall()
            connection.close()
            return result[0][0]
        
    def request_feed_update(self):
        """
        Request backend to fetch and update all feeds. This function returns 
        immediately.
        """
        self.backend_connection.request_feed_update()

################################################################################

class Feed(object):
    """
    Objects from this class represents feeds. Feeds has entries, title etc.
    """
    
    # Feed cache database
    FEED_DB = os.path.expanduser('~/.entertainer/cache/feed.db')
        
    def __init__(self, url):
        """
        Initialize Feed object.
        @param url: URL of the feed
        """
        self.url = url
        self.entries = []
        connection = sqlite.connect(self.__class__.FEED_DB)
        cursor = connection.cursor()
        cursor.execute("""SELECT title, subtitle, description, time, date 
                          FROM feed 
                          WHERE url=:url""",
                          { "url" : self.url })
        result = cursor.fetchall()
        self.title = result[0][0]
        self.subtitle = result[0][1]
        self.description = result[0][2]
        self.time = result[0][3]
        self.date = result[0][4]
        cursor.execute("""SELECT title, description, id, time, date 
                          FROM entry 
                          WHERE entry.feed_url=:url""",
                          { "url" : self.url })
        for row in cursor:
            self.entries.append(Entry(row[0], row[1], row[2], row[3], row[4]))
        connection.close()
    
    def get_title(self):
        """
        Get title ot the feed
        @return Title as string
        """
        return self.title
        
    def get_description(self):
        """
        Get description of the feed.
        @return description as string
        """
        return self.description
        
    def get_entries(self):
        """
        Get all entries of this feed.
        @return List of Entry objects
        """
        return self.entries
    
    def get_entry(self, id):
        """
        Get a specific entry from this feed.
        @param id: ID of the entry
        @return: Entry object
        """
        for entry in self.entries:
            if entry.get_id() == id:
                return entry
        
    def get_number_of_unread(self):
        """
        Get number of unread entries in this feed.
        @return Integer - number of unread entries
        """
        connection = sqlite.connect(self.__class__.FEED_DB)
        cursor = connection.cursor()
        cursor.execute("""SELECT COUNT(feed_url) 
                          FROM   entry 
                          WHERE  isread='NO'
                          AND    feed_url=:url""",
                          { "url" : self.url })
        result = cursor.fetchall()
        connection.close()
        return int(result[0][0])
        
    def get_subtitle(self):
        """
        Get feed's subtitle. 
        @return: String
        """
        return self.subtitle
        
    def get_feed_url(self):
        """
        Get URL of the feed
        @return: String
        """
        return self.url
        
    def get_time(self):
        """
        Get time
        @return: String
        """
        return self.time
        
    def get_date(self):
        """
        Get date
        @return: String
        """
        return self.date

################################################################################

class Entry(object):
    """
    Entry is a one post of the feed. This is a simple container class for entry.
    """
    
    def __init__(self, title, description, id, time, date):
        """
        Initialize Entry object.
        @param title: Title of the entry
        @param description: Description of the entry
        @param id: Entry ID
        @param time: Time of the entry (when this was submitted)
        @param date: Date of the entry (when this was submitted)
        """
        self.title = title
        self.description = description
        self.id = id
        self.time = time
        self.date = date
    
    def get_title(self):
        """
        Get title ot the entry.
        @return: String
        """
        return self.title
        
    def get_description(self):
        """
        Get description of the entry
        @return: String 
        """
        return self.description

    def get_id(self):
        """
        Get entry ID
        @return: String
        """
        return self.id

    def get_time(self):
        """
        Get time.
        @return: String
        """
        return self.time
        
    def get_date(self):
        """
        Get date.
        @return: String
        """
        return self.date
    
